package com.bookmall.action;

import com.bookmall.MallConst;
import com.bookmall.dao.BookDAO;
import com.bookmall.dao.OrderDAO;
import com.bookmall.model.Book;
import com.bookmall.model.BookSearchRequest;
import com.bookmall.model.Order;
import com.sun.org.apache.xpath.internal.operations.Or;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by Squking on 2018/5/6.
 */
@Controller
public class BookController {
    private static final int NumberPerPage = 10;
    private List<Book> listAllBook;
    private HashMap<String, BookSearchResult> mapSessionId2searchBooks = new HashMap<String, BookSearchResult>();
    private HashMap<String, Order> mapSessionId2order = new HashMap<>();
    private HashMap<String, List<Order>> mapLogname2orders = new HashMap<>();

    @RequestMapping(value = "/showBooks", method = RequestMethod.GET)
    public ModelAndView showBooksByPage(HttpSession httpSession)
    {
        return showBooksByPage(0, httpSession);
    }

    @RequestMapping(value = "/showBooks/{page}", method = RequestMethod.GET)
    public ModelAndView showBooksByPage(@PathVariable("page") int page, HttpSession httpSession)
    {
        ModelAndView modelAndView;
        boolean isLogin = httpSession.getAttribute(MallConst.SessionKey_LoginName) != null;
        if (isLogin)
        {
            checkSearchAllBooks();
            int total = listAllBook.size();
            int totalPage = (int)Math.ceil((float)total / NumberPerPage);
            if (page < 0 || page >= totalPage)
            {
                modelAndView = new ModelAndView("message");
                modelAndView.addObject("message", "找不到当前页");
            }
            else
            {
                List<Book> listBook = new ArrayList<>(NumberPerPage);
                for (int i = 0, j = page * NumberPerPage; i < NumberPerPage && j < total; ++i, ++j)
                {
                    listBook.add(listAllBook.get(j));
                }
                modelAndView = new ModelAndView("showBooks");
                modelAndView.addObject("listBook", listBook);
                modelAndView.addObject("page", page);
                modelAndView.addObject("totalPage", totalPage);
            }
        }
        else
        {
            modelAndView = new ModelAndView("message");
            modelAndView.addObject("message", "请先登录");
        }
        return modelAndView;
    }

    @RequestMapping(value = "/searchBooks", method = RequestMethod.GET)
    public ModelAndView searchBooks(HttpSession httpSession)
    {
        return searchBooksByKeyword("", 0, 0, 0, httpSession);
    }

    @RequestMapping(value = "/searchBooks/{page}", method = RequestMethod.GET)
    public ModelAndView searchBooksByPage(@PathVariable("page") int page, HttpSession httpSession)
    {
        BookSearchRequest request = new BookSearchRequest();
        ModelAndView modelAndView = new ModelAndView("searchBooks");
        BookSearchResult result = mapSessionId2searchBooks.get(httpSession.getId());
        request.setKeywords(result.getKeywords());
        request.setContentType(result.getContentType());
        request.setMatchType(result.getMatchType());
        modelAndView.addObject("command", request);
        modelAndView.addObject("page", page);
        List<Book> listSearchBook = result.getListBook();
        int searchBookCount = listSearchBook.size();
        List<Book> listBook = new ArrayList<>(NumberPerPage);
        for (int i = page * NumberPerPage, j = 0; i < searchBookCount && j < NumberPerPage; i++, j++) {
            listBook.add(listSearchBook.get(i));
        }
        modelAndView.addObject("listBook", listBook);
        int totalPage = (int) Math.ceil((float)searchBookCount / NumberPerPage);
        modelAndView.addObject("totalPage", totalPage);
        return modelAndView;
    }

    @RequestMapping(value = "/action/searchBooks", method = RequestMethod.POST)
    public ModelAndView searchBooksByRequest(BookSearchRequest request, HttpSession httpSession)
    {
        return searchBooksByKeyword(request.getKeywords(), request.getMatchType(), request.getContentType(), 0, httpSession);
    }

    @RequestMapping(value = "/action/addToCart/{ISBN}", method = RequestMethod.POST)
    public String addBookToCart(@PathVariable("ISBN") String ISBN, HttpSession httpSession, ModelMap model)
    {
        Object loginName = httpSession.getAttribute(MallConst.SessionKey_LoginName);
        if (loginName != null)
        {
            checkSearchAllBooks();
            String sessionId = httpSession.getId();
            Order order;
            if (mapSessionId2order.containsKey(sessionId))
            {
                order = mapSessionId2order.get(sessionId);
            }
            else
            {
                order = createNewOrder(loginName.toString());
                mapSessionId2order.put(sessionId, order);
            }
            for (int i = 0; i < listAllBook.size(); i++) {
                Book book = listAllBook.get(i);
                if (book.getISBN().equals(ISBN))
                {
                    order.addBook(book);
                    order.setOrderContent(order.listBook2contentString());
                    order.recalcSum();
                    break;
                }
            }
            model.addAttribute("message", "添加成功");
        }
        else
        {
            model.addAttribute("message", "请先登录");
        }
        return "message";
    }

    @RequestMapping(value = "/showCart", method = RequestMethod.GET)
    public ModelAndView showCart(HttpSession httpSession)
    {
        ModelAndView modelAndView;
        boolean isLogin = httpSession.getAttribute(MallConst.SessionKey_LoginName) != null;
        if (isLogin)
        {
            String sessionId = httpSession.getId();
            Order order;
            if (mapSessionId2order.containsKey(sessionId))
            {
                order = mapSessionId2order.get(sessionId);
            }
            else
            {
                String logname = httpSession.getAttribute(MallConst.SessionKey_LoginName).toString();
                order = createNewOrder(logname);
                mapSessionId2order.put(sessionId, order);
            }
            modelAndView = new ModelAndView("showCart", "command", order);
        }
        else
        {
            modelAndView = new ModelAndView("message");
            modelAndView.addObject("message", "请先登录");
        }
        return modelAndView;
    }

    @RequestMapping(value = "/action/buyCart", method = RequestMethod.POST)
    public String buyCart(HttpSession httpSession, ModelMap model)
    {
        Object loginName = httpSession.getAttribute(MallConst.SessionKey_LoginName);
        if (loginName != null)
        {
            String sessionId = httpSession.getId();
            Order order = null;
            if (mapSessionId2order.containsKey(sessionId))
            {
                order = mapSessionId2order.get(sessionId);
                mapSessionId2order.remove(sessionId);
                OrderDAO orderDAO = new OrderDAO();
                try {
                    orderDAO.insert(order);
                    List<Order> listOrder = getAllOrders(loginName.toString());
                    listOrder.add(order);
                    model.addAttribute("message", "购买成功");
                } catch (Exception e) {
                    model.addAttribute("message", e.getMessage());
                }
            }
            else
            {
                model.addAttribute("message", "请先把书加入购物车");
            }
        }
        else
        {
            model.addAttribute("message", "请先登录");
        }
        return "message";
    }

    @RequestMapping(value = "/showOrder", method = RequestMethod.GET)
    public ModelAndView showOrder(HttpSession httpSession)
    {
        ModelAndView modelAndView;
        boolean isLogin = httpSession.getAttribute(MallConst.SessionKey_LoginName) != null;
        if (isLogin)
        {
            String logname = httpSession.getAttribute(MallConst.SessionKey_LoginName).toString();
            List<Order> listOrder = getAllOrders(logname);
            modelAndView = new ModelAndView("showOrder");
            modelAndView.addObject("listOrder", listOrder);
        }
        else
        {
            modelAndView = new ModelAndView("message");
            modelAndView.addObject("message", "请先登录");
        }
        return modelAndView;
    }

    private ModelAndView searchBooksByKeyword(String keywords, int matchType, int contentType, int page,
                                             HttpSession httpSession)
    {
        ModelAndView modelAndView;
        boolean isLogin = httpSession.getAttribute(MallConst.SessionKey_LoginName) != null;
        if (isLogin)
        {
            BookSearchRequest request = new BookSearchRequest();
            modelAndView = new ModelAndView("searchBooks");
            int totalPage = 0;
            if (keywords.length()> 0)
            {
                String sessionId = httpSession.getId();
                List<Book> listSearchBook;
                if (mapSessionId2searchBooks.containsKey(sessionId))
                {
                    listSearchBook = mapSessionId2searchBooks.get(sessionId).getListBook();
                }
                else
                {
                    listSearchBook = searchBooksByKeyword(keywords, BookSearchRequest.KeywordMatchType.values()[matchType], BookSearchRequest.BookContentType.values()[contentType]);
                    BookSearchResult result = new BookSearchResult();
                    result.setKeywords(keywords);
                    result.setMatchType(matchType);
                    result.setContentType(contentType);
                    result.setListBook(listSearchBook);
                    mapSessionId2searchBooks.put(sessionId, result);
                }
                int searchBookCount = listSearchBook.size();
                totalPage = (int) Math.ceil((float)searchBookCount / NumberPerPage);
                List<Book> listBook = new ArrayList<>(NumberPerPage);
                for (int i = page * NumberPerPage, j = 0; i < searchBookCount && j < NumberPerPage; i++, j++) {
                    listBook.add(listSearchBook.get(i));
                }
                modelAndView.addObject("listBook", listBook);
            }
            request.setKeywords(keywords);
            request.setContentType(contentType);
            request.setMatchType(matchType);
            modelAndView.addObject("command", request);
            modelAndView.addObject("page", page);
            modelAndView.addObject("totalPage", totalPage);
        }
        else
        {
            modelAndView = new ModelAndView("message");
            modelAndView.addObject("message", "请先登录");
        }
        return modelAndView;
    }

    private List<Book> searchBooksByKeyword(String keyword, BookSearchRequest.KeywordMatchType matchType, BookSearchRequest.BookContentType contentType)
    {
        checkSearchAllBooks();
        List<Book> listBook = new ArrayList<>();
        for (int i = 0; i < listAllBook.size(); i++) {
            Book book = listAllBook.get(i);
            boolean containsKeyword = false;
            switch (contentType)
            {
                case ISBN:
                    containsKeyword = containsKeyword(book.getISBN(), keyword, matchType);
                    break;
                case AUTHOR:
                    containsKeyword = containsKeyword(book.getAuthor(), keyword, matchType);
                    break;
                case NAME:
                    containsKeyword = containsKeyword(book.getName(), keyword, matchType);
                    break;
            }
            if (containsKeyword)
            {
                listBook.add(book);
            }
        }
        return listBook;
    }

    private boolean containsKeyword(String value, String keyword, BookSearchRequest.KeywordMatchType matchType)
    {
        switch (matchType)
        {
            case PREFIX:
                return value.startsWith(keyword);
            case POSTFIX:
                return value.endsWith(keyword);
            case CONTAINS:
                return value.contains(keyword);
        }
        return false;
    }

    private void checkSearchAllBooks()
    {
        if (listAllBook == null)
        {
            BookDAO bookDAO = new BookDAO();
            try {
                listAllBook = bookDAO.getAllBooks();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private List<Order> getAllOrders(String logname)
    {
        List<Order> listOrder = null;
        if (mapLogname2orders.containsKey(logname))
        {
            listOrder = mapLogname2orders.get(logname);
        }
        else
        {
            checkSearchAllBooks();
            OrderDAO orderDAO = new OrderDAO();
            try {
                listOrder = orderDAO.getAllOrders(logname);
                mapLogname2orders.put(logname, listOrder);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return listOrder;
    }

    private Order createNewOrder(String logname)
    {
        Order order = new Order();
        int maxOrderNum = 0;
        List<Order> listOrder = getAllOrders(logname);
        if (listOrder != null)
        {
            for (int i = listOrder.size() - 1; i >= 0; i--) {
                int orderNum = listOrder.get(i).getOrderNum();
                if (orderNum > maxOrderNum)
                {
                    maxOrderNum = orderNum;
                }
            }
        }
        order.setOrderNum(maxOrderNum + 1);
        order.setLogname(logname);
        return order;
    }

    public class BookSearchResult extends BookSearchRequest{
        private List<Book> listBook;

        public List<Book> getListBook() {
            return listBook;
        }

        public void setListBook(List<Book> listBook) {
            this.listBook = listBook;
        }
    }
}
